function timeout(ms) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(), ms);
    })
}


const template = `
<div>
    <button />
</div>
`

function traverse(ele, rootSprite) {
    const children = ele.children;

    for (let eleitem of children) {
        const lowwerTagName = eleitem.tagName.toLowerCase();
        const sprite = new PIXI.Sprite(PIXI.Texture.EMPTY);
        if (this.$components.has(lowwerTagName)) {
            this.$children.push(new HtmlCompile(this.$components.get(lowwerTagName), eleitem, sprite));
        } else {
            if (eleitem.children.length !== 0) {
                traverse(eleitem, sprite);
            }
        }
        rootSprite.addChild(sprite);
    }
}

class HtmlCompile {
    /**
     * 
     * @param {object} options 
     * @param {string} options.value - base64
     * @param {string} options.template - html模版字符串
     * @param {Object<string, HtmlCompile>} options.components
     * @param {() => Object<string, any>} options.data
     * @param {}
     * @param {HTMLElement} ele 
     * @param {PIXI.Sprite} sprite 
     */
    constructor(options, slotEle, sprite) {
        this.$el = null;
        this.$sprite = sprite ? sprite : new PIXI.Sprite(PIXI.Texture.EMPTY);
        this.$options = options;
        this.$components = new Map;
        this.$children = [];
        // 如果是子组件，eg.. <login /> 那么$slotEle就是<login />
        this.$slotEle = slotEle;

        this.$data = null;

        if (options && options.components) {
            for (const key of Object.keys(options.components)) {
                if (this.$components.has(key)) {
                    if (process.env === 'development') {
                        throw new Error(`组件名${key}重复`);
                    }
                } else {
                    this.$components.set(key, options.components[key]);
                }
            }
        }

        this.compile();
    }

    compile() {
        const root = document.createElement('div');
        root.innerHTML = this.$options.template;
        this.$el = root.children[0];
        traverse.call(this, this.$el, this.$sprite);
    }

    async next() {
        await this.init();
        for (let child of this.$children) {
            await child.next();
        }

    }

    async init() {
        const { value, data } = this.$options;
        if (data instanceof Function) {
            this.$data = data();
        }
        if (value) {
            console.log(this);
            const image = await loadBase64(value);
            const texture = imageToTexture(image);
            this.$sprite.texture = texture;
        }
    }
}
const sprite = new PIXI.Sprite(PIXI.Texture.EMPTY);
const vm = new HtmlCompile({
    template,
    value: box_base64,
    components: {
        button: {
            template: '<div></div>',
            value: button_base64,
        }
    }
});

async function main() {
    await vm.next();
    const application = new PIXI.Application();
    document.body.appendChild(application.view);
    application.stage.addChild(vm.$sprite);
}
main();